﻿using AuSys.Models.Identities;
using AuSys.Repos.Identities;
using AuSys.Services.App.UserInfo.Abstractions;
using System.IdentityModel.Tokens.Jwt;

namespace AuSys.Services.App.UserInfo
{
    public class HttpUserInfoService : IUserInfoService
    {
        private Lazy<IUserInfo> UserInfo { get; }
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IUserIdProvider _userIdProvider;
        private readonly IBasicUserInfoProvider _basicUserInfoProvider;
        public HttpUserInfoService(
            IBasicUserInfoProvider basicUserInfoProvider,
            IHttpContextAccessor httpContextAccessor,
            IUserIdProvider userId)
        {
            _httpContextAccessor = httpContextAccessor;
            _userIdProvider = userId;
            _basicUserInfoProvider = basicUserInfoProvider;
            UserInfo = new(ReadUserInfo);
        }

        private HttpUserInfo ReadUserInfo()
        {
            var id = _userIdProvider.GetUserId();
            string name = string.Empty;
            int leftHours = 0;
            UserType type = UserType.Tourist;
            var ctx = _httpContextAccessor.HttpContext
                ?? throw new Exception("httpContext获取失败");
            if (id > 0)
            {
                var user = _basicUserInfoProvider.GetUserInfoBasic(id);
                if (user is not null)
                {
                    name = user.Name ?? "??";
                    type = user.Type;
                }
            }
            var expClaim = ctx.User.Claims.FirstOrDefault(x => x.Type == JwtRegisteredClaimNames.Exp);
            if (expClaim is not null && long.TryParse(expClaim.Value, out long exp))
            {
                long now = DateTimeOffset.Now.ToUnixTimeSeconds();
                long leftSeconds = exp - now;
                leftHours = (int)(leftSeconds / 3600);
            }
            var info = new HttpUserInfo(id, name, leftHours, type);
            foreach(var c in ctx.User.Claims)
                info.Claims.Add(c.Type, c.Value);
            return info;
        }
        public IUserInfo GetUserInfo()
            => UserInfo.Value;
    }

    public class HttpUserInfo(
        int id, string name, int leftHours, UserType userType
        ) : IUserInfo
    {
        public int Id { get; } = id;
        public string Name { get; set; } = name;
        public int LeftHours { get; set; } = leftHours;
        public UserType Type { get; set; } = userType;
        public bool IsAdmin => Type >= UserType.Admin;
        public bool NotAdmin => !IsAdmin;
        public Dictionary<string, string> Claims { get; } = [];
    }
}
